package cn.agiledata.bank.linkbank.service;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.BeanComparator;
import org.apache.commons.collections.ComparatorUtils;
import org.apache.commons.collections.comparators.ComparableComparator;
import org.apache.commons.collections.comparators.ComparatorChain;
import org.bouncycastle.util.encoders.Base64;

import ccit.security.bssp.CAUtility;
import ccit.security.bssp.ex.CrypException;
import cn.agiledata.bank.account.service.IAccountService;
import cn.agiledata.bank.common.dao.AccountTemplate;
import cn.agiledata.bank.common.dao.BankDao;
import cn.agiledata.bank.common.dao.TransactionTemplate;
import cn.agiledata.bank.common.util.Constant;
import cn.agiledata.bank.common.util.DateUtil;
import cn.agiledata.bank.common.util.ForeDict;
import cn.agiledata.bank.common.util.IOUtil;
import cn.agiledata.bank.common.util.MD5;
import cn.agiledata.bank.common.util.SignUtil;
import cn.agiledata.bank.common.util.StringUtil;
import cn.agiledata.bank.common.util.UniqueIdentityUtil;
import cn.agiledata.bank.common.util.WeatherUtil;
import cn.agiledata.bank.hibernateBean.Account;
import cn.agiledata.bank.hibernateBean.ActionType;
import cn.agiledata.bank.hibernateBean.Bank;
import cn.agiledata.bank.hibernateBean.SubAccount;
import cn.agiledata.bank.hibernateBean.Transaction;
import cn.agiledata.bank.linkbank.exception.LinkBankException;
import cn.agiledata.bank.linkbank.form.WebPayRequestForm;
import cn.agiledata.bank.linkbank.logic.payment.UnsPayRequest;
import cn.agiledata.bank.linkbank.logic.payment.UnsPayResponse;
import cn.agiledata.bank.transaction.dao.ActionTypeDao;
import cn.agiledata.bank.transaction.service.FeeRatioInterf;
import cn.agiledata.bank.transaction.service.GetTransactionImpl;
import cn.agiledata.bank.transaction.service.TransactionFactory;

import com.vnv.infrastructure.logic.IPBAppFactory;
import com.vnv.infrastructure.logic.IPBMgrFactory;

/**
 * @author maxianbo
 * 
 */
public final class WebPayServiceImpl implements WebPayService {

    private AccountTemplate accountTemplate;

    private BankDao bankDao;

    private TransactionTemplate transactionTemplate;

    private ActionTypeDao actionTypeDao;

    private BankNetPayService bankB2cNetPayService;

    private BankNetPayService bankB2bNetPayService;

    private BankTelPayService bankTelPayService;

    public void setAccountTemplate(AccountTemplate accountTemplate) {
        this.accountTemplate = accountTemplate;
    }

    public void setBankDao(BankDao bankDao) {
        this.bankDao = bankDao;
    }

    public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
        this.transactionTemplate = transactionTemplate;
    }

    public void setActionTypeDao(ActionTypeDao actionTypeDao) {
        this.actionTypeDao = actionTypeDao;
    }

    public void setBankB2cNetPayService(BankNetPayService bankNetPayService) {
        this.bankB2cNetPayService = bankNetPayService;
    }

    public void setBankB2bNetPayService(BankNetPayService bankB2bNetPayService) {
        this.bankB2bNetPayService = bankB2bNetPayService;
    }

    public void setBankTelPayService(BankTelPayService bankTelPayService) {
        this.bankTelPayService = bankTelPayService;
    }

    public UnsPayRequest getUnsPayRequest(WebPayRequestForm form,
			UnsPayRequest upRequest) {
    	// zln 修正 20080707 解决FireFox无法取得Session中Form内容的问题
        if ((form == null || form.getMerchantId() == null)
        		&& upRequest == null)
            return null;
        
        UnsPayRequest unsPayRequest = null;
        if(upRequest == null && form.getMerchantId() != null) {
        	// IE
	        unsPayRequest = new UnsPayRequest();
	        Account account = this.accountTemplate.getAccountByAccountId(form
	                .getMerchantId());
	        unsPayRequest.setCreditAccount(account);
	        
	        //wuping add  付款账户
	        String theId=form.getTheId();
	        SubAccount debitAccount = this.accountTemplate
            .getSubAccountByAccountId(theId);
	        unsPayRequest.setDebitSubAccount(debitAccount);
	        //
	        String subAccountId = form.getSubAccountId();
	        if (subAccountId != null && subAccountId.length() > 0) {
	            SubAccount subAccount = this.accountTemplate
	                    .getSubAccountBySubAccountId(subAccountId);
	            unsPayRequest.setCreditSubAccount(subAccount);
	        }
	        
	        
	        unsPayRequest.setOrderId(form.getOrderId());
	        BigDecimal amount = form.getAmount() == null ? null : new BigDecimal(
	                form.getAmount());
	        int responseMode = Constant.RESPONSE_MODE_NEVER;
	        try {
	            responseMode = Integer.parseInt(form.getResponseMode());
	        } catch (NumberFormatException e) {
	        }
	        unsPayRequest.setResponseMode(responseMode);
	        unsPayRequest.setAmount(amount);
	        unsPayRequest.setMerchantUrl(form.getMerchantUrl());
	        unsPayRequest.setRemark(form.getRemark());
	        unsPayRequest.setCurrencyType(Constant.CURRENCY_RMB);
	        unsPayRequest.setAssuredPay(form.isAssured());
	        Date time = DateUtil.string2Date(form.getTime(), ORDER_TIME_FORMAT);
	        if (time == null)
	            time = new Date();
	        unsPayRequest.setTime(time);
	        unsPayRequest.setMerchantMac(form.getMac());
	        unsPayRequest.setMerchantParam(form.getMerchantParam());
	        unsPayRequest.setCommodity(form.getCommodity());
	        unsPayRequest.setOrderUrl(form.getOrderUrl());
	        Bank bank = this.bankDao.getBankByCode(form.getBankCode());
	        unsPayRequest.setBank(bank);
	
	        // 支付链特定项
	        unsPayRequest.setDebitName(form.getDebitName());
	        String debit = form.getDebit();
	        if (debit != null) {
	            if (StringUtil.isEmail(debit)) {
	                unsPayRequest.setDebitEmail(debit);
	            }
	            if (StringUtil.isMobile(debit)) {
	                unsPayRequest.setDebitMobile(debit);
	            }
	        }
        }
        else {
        	// FireFox
        	unsPayRequest = upRequest;
        	Account account = this.accountTemplate.getAccount(String
					.valueOf(unsPayRequest.getCreditAccount().getId()));
	        unsPayRequest.setCreditAccount(account);
        	 Bank bank = this.bankDao.getBankByCode(form.getBankCode());
 	        unsPayRequest.setBank(bank);
        }

        return unsPayRequest;
    }

    public void setActionType(UnsPayRequest unsPayRequest, String actionTypeCode) {
        ActionType actionType = this.actionTypeDao
                .getActionTypeByCode(actionTypeCode);
        unsPayRequest.setActionType(actionType);
    }

    public UnsPayResponse getUnsPayResponse(UnsPayRequest unsPayRequest,
            boolean requiredSave) {
        String accountId = unsPayRequest.getCreditAccount().getAccountId();
        String orderId = unsPayRequest.getOrderId();
        BigDecimal amount = unsPayRequest.getAmount();
        String merchantUrl = unsPayRequest.getMerchantUrl();
        int responseMode = unsPayRequest.getResponseMode();
        String transId = getTransId(accountId, orderId);
        UnsPayResponse unsPayResponse = new UnsPayResponse(accountId, orderId,
                amount, merchantUrl, responseMode);
        if (requiredSave) {
            Transaction trans = saveTransaction(transId, unsPayRequest);
            unsPayResponse.setUnsTransId(trans.getTransId());
        } else {
            unsPayResponse.setUnsTransId(transId);
        }
        String accountKey = unsPayRequest.getCreditAccount().getKey();
        unsPayResponse.setAccountKey(accountKey);
        if (unsPayRequest.isAssuredPay()) {
            // 担保交易返回买方已付款
            unsPayResponse.setReturnCode(UnsPayResponse.RETURN_CODE_PAID);
        }
        return unsPayResponse;
    }

    public boolean containsSubAccount(Account account, String subAccountId) {
        for (Iterator it = account.getSubAccounts().iterator(); it.hasNext();) {
            SubAccount subAccount = (SubAccount) it.next();
            if (subAccount.getAccountId().equals(subAccountId)) {
                return true;
            }
        }
        return false;
    }

    public Account validateAccount(String accountId, String subAccountId)
            throws LinkBankException {
        Account account = this.accountTemplate.getAccountByAccountId(accountId);
        if (account == null
                || !Constant.ACCOUNT_STATE_NORMAL.equals(account.getStatus())) {
            throw new LinkBankException("error.merchant.invalid_account",
                    accountId, "0201");
        }
        
        IAccountService acctService = (IAccountService) IPBAppFactory
				.getObj("accountService");
        if(acctService.checkBlackList(account.getEmail())) {
        	// 黑名单商户，禁止交易
        	
        	// 发送邮件通知
        	this.accountTemplate.sendMail("0", "黑名单商户网关交易", account.getEmail());
        	
        	// 记录异常日志
        	this.accountTemplate.saveLog(account, "0", "黑名单商户网关交易");
        	
        	throw new LinkBankException("error.merchant.blacklist",
                    accountId, "0202");
        }
        
        if (subAccountId != null && subAccountId.length() > 0
                && !containsSubAccount(account, subAccountId)) {
            throw LinkBankException.getNotContainsSubAccountException(
                    accountId, subAccountId);
        }
        return account;
    }

    public String validateOrderId(String accountId, String orderId)
            throws LinkBankException {
        Transaction tran = this.transactionTemplate
                .getTransactionByOrderIdAndAccountId(orderId, accountId);
        if (tran != null) {
            String transStatus = tran.getTransStatus();
            if (Constant.TRANS_STATUS_TRANSACTIONSUCCESS.equals(transStatus)) {
                throw new LinkBankException(
                        "error.merchant.existed_orderId_successful", orderId,
                        "0202");
            }
            if (Constant.TRANS_STATUS_WAITFORBUYER.equals(transStatus)) {
                throw new LinkBankException(
                        "error.merchant.existed_orderId_paid", orderId, "0203");
            }
        }
        return tran == null ? null : tran.getTransId();
    }

    private String getTransId(String accountId, String orderId) {
        Transaction tran = this.transactionTemplate
                .getTransactionByOrderIdAndAccountId(orderId, accountId);
        return tran == null ? null : tran.getTransId();
    }

    public void validateMac(Map parameters, String mac)
            throws LinkBankException {
        if (mac != null) {
            String accountId = (String) parameters.get("merchantId");
            String merchantKey = getAccountKey(accountId);
            if (merchantKey == null)
                merchantKey = "";
            parameters.put("merchantKey", merchantKey);
            String[] keys = { "merchantId", "merchantUrl", "responseMode",
                    "orderId", "currencyType", "amount", "assuredPay", "time",
                    "remark","theId", "merchantKey" };
            if (!mac.equalsIgnoreCase(getMac(keys, parameters))) {
                throw new LinkBankException("error.merchant.unmatched_mac",
                        new Object[] {}, "0204");
            }
        }
    }
    
    /**
     * 根据证书验签
     * 
     * @param parameters
     * @param sign
     * @throws LinkBankException
     */
    public void validateSign(Map parameters, String sign)
            throws LinkBankException {
    	// FIXME 证书验签
    	int ret = -1;
        try {
			if (sign != null) {
			    String accountId = (String) parameters.get("merchantId");
			    String merchantKey = getAccountKey(accountId);
			    if (merchantKey == null)
			        merchantKey = "";
			    parameters.put("merchantKey", merchantKey);
			    String[] keys = { "merchantId", "merchantUrl", "responseMode",
			            "orderId", "currencyType", "amount", "assuredPay", "time",
			            "remark","theId", "merchantKey" };
			    
			    // 读取证书
			    InputStream in = Constant.class.getClassLoader().getResourceAsStream("cert/" + accountId + ".der");
				ByteArrayOutputStream bos = new ByteArrayOutputStream();
				int buf_size = 1024;
				byte[] buffer = new byte[buf_size];
				int len = 0;
				while (-1 != (len = in.read(buffer, 0, buf_size))) {
					bos.write(buffer, 0, len);
				}
				byte[] cert = bos.toByteArray();
				ret = CAUtility.verifyWithCert(0x00000103, cert, linkParameters(keys, parameters).getBytes(), Base64.decode(sign));
				
				System.out.println("verify sign result:" + ret);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
        
        if(ret != 0) {
            throw new LinkBankException("error.merchant.signerror",
                    new Object[] {}, "0204");
        }
    }
    
    public void validateReturnMac(Map parameters, String mac) throws LinkBankException {
		if (mac != null) {
			String accountId = (String) parameters.get("merchantId");
			String merchantKey = getAccountKey(accountId);
			if (merchantKey == null)
				merchantKey = "";
			parameters.put("merchantKey", merchantKey);
			String[] keys = { "merchantId", "merchantUrl", "orderId", "amount", "merchantKey" };
			if (!mac.equalsIgnoreCase(getMac(keys, parameters))) {
				throw new LinkBankException("error.merchant.unmatched_mac", new Object[] {}, "0204");
			}
		}
	}
    /**
     * 验证金额
     */
    public void validateAmount(String amount) throws LinkBankException {
    	double dAmount = Double.parseDouble(amount);
    	if(dAmount <= 0.00) {
    		throw new LinkBankException("error.merchant.amountltzero",
                    new Object[] {}, "0205");
    	}
    }
    /**
     * 验证费用是否大于金额
     * @param amount
     * @param account
     * @param actionType
     * @throws LinkBankException
     */
    public boolean validateFee(BigDecimal amount,Account account,String actionType){
    	double dAmount = amount.doubleValue();
       	FeeRatioInterf feeService = (FeeRatioInterf) IPBMgrFactory.getMgr(ForeDict.SERVICE_FEE_RATIO);
        double creditFee = feeService.getCreditFee(null,account, actionType, new Double(dAmount));//收款方手续费
        if(dAmount - creditFee <0) {
        	return false;
        }
        return true;
    }

    private String linkParameters(String[] keys, Map parameters) {
        String s = "";
        s += keys[0] + "=" + parameters.get(keys[0]);
        for (int i = 1; i < keys.length; i++) {
            Object value = parameters.get(keys[i]);
            if (value != null)
                s += "&" + keys[i] + "=" + value;
        }
        return s;
    }

    /**
     * 获取指定参数根据指定关键字拼凑后得到的mac值
     * 
     * @param keys
     *            顺序有关的关键字
     * @param parameters
     *            参数
     * @return 指定参数根据指定关键字拼凑后得到的mac值
     */
    private String getMac(String[] keys, Map parameters) {
        return new MD5().getMD5ofStr(linkParameters(keys, parameters));
    }

    private Map getParametersNoMac(UnsPayResponse unsPayResponse,
            int responseMode) {
        Map parameters = new HashMap();
        parameters.put("merchantId", unsPayResponse.getAccountId());
        parameters.put("responseMode", String.valueOf(responseMode));
        parameters.put("orderId", unsPayResponse.getOrderId());
        parameters.put("currencyType", unsPayResponse.getCurrencyType());
        BigDecimal amount = unsPayResponse.getAmount();
        if (amount == null) {
            amount = new BigDecimal(0.0d).setScale(2);
        }
        parameters.put("amount", amount.toString());
        parameters.put("returnCode", unsPayResponse.getReturnCode());
        parameters.put("returnMessage", unsPayResponse.getReturnMessage());
        parameters.put("merchantKey", unsPayResponse.getAccountKey());
        return parameters;
    }

    public String generateMac(UnsPayResponse unsPayResponse, int responseMode) {
        Map parameters = getParametersNoMac(unsPayResponse, responseMode);
        String[] keys = { "merchantId", "responseMode", "orderId",
                "currencyType", "amount", "returnCode", "returnMessage",
                "merchantKey" };
        return getMac(keys, parameters);
    }
    
    public String generateSign(UnsPayResponse unsPayResponse, int responseMode) {
        Map parameters = getParametersNoMac(unsPayResponse, responseMode);
        String[] keys = { "merchantId", "responseMode", "orderId",
                "currencyType", "amount", "returnCode", "returnMessage",
                "merchantKey" };
        return getSign(keys, parameters);
    }
    
    private String getSign(String[] keys, Map parameters) {
        return SignUtil.sign(linkParameters(keys, parameters));
    }

    public void backgroundResponse(UnsPayResponse unsPayResponse)
            throws IOException {
        int responseMode = Constant.RESPONSE_MODE_BACKGROUND;
        Map parameters = getParametersNoMac(unsPayResponse, responseMode);
        parameters.put("mac", generateMac(unsPayResponse, responseMode));
        parameters.put("unsTransId", unsPayResponse.getUnsTransId());
        //网关响应多次通知
        IOUtil.postNetReturnUrl(unsPayResponse.getMerchantUrl(), parameters);
    }

    private boolean isMerchantTrans(Transaction trans) {
        return trans != null && trans.getOrderId() != null
                && trans.getOrderId().length() > 0
                && trans.getSellerUrl() != null
                && trans.getSellerUrl().length() > 0
                && trans.getSellerParam() != null
                && trans.getSellerParam().length() > 0;
    }

    /**
     * 交易状态转换为返回码
     * 
     * @param transStatus
     *            交易状态
     * @return 返回码
     */
    private String transStatus2ReturnCode(String transStatus) {
        if (Constant.TRANS_STATUS_TRANSACTIONSUCCESS.equals(transStatus)) {
            return "0000";
        } else if (Constant.TRANS_STATUS_WAITFORBUYER.equals(transStatus)) {
            return "0001";
        } else if (Constant.TRANS_STATUS_WAITFORBUYERAFFIRM.equals(transStatus)) {
            return "0002";
        } else if (Constant.TRANS_STATUS_TRANSACTIONCLOSE.equals(transStatus)) {
            return "0006";
        } else if (Constant.TRANS_STATUS_APPLYREFUND.equals(transStatus)) {
            return "0007";
        } else if (Constant.TRANS_STATUS_DISPUTED.equals(transStatus)) {
            return "0008";
        } else if (Constant.TRANS_STATUS_REFUNDSUCC.equals(transStatus)) {
            return "0009";
        } else if (Constant.TRANS_STATUS_WAITEBANKFEEDBACK.equals(transStatus)) {
            return "0011";
        } else {
            return "";
        }
    }

    private void backgroundResponseTransaction(Transaction trans)
            throws LinkBankException {
        if (isMerchantTrans(trans)) {
            String returnCode = transStatus2ReturnCode(trans.getTransStatus());
            if (returnCode == null || returnCode.length() == 0) { // 只有有效返回码才向商户反馈
                return;
            }
            Map parameters = new HashMap();
            Account account = trans.getCredit().getAccount();
            parameters.put("merchantId", account.getAccountId());
            parameters.put("responseMode", String
                    .valueOf(Constant.RESPONSE_MODE_BACKGROUND));
            parameters.put("orderId", trans.getOrderId());
            parameters.put("currencyType", trans.getCurrency());
            BigDecimal amount = new BigDecimal(trans.getAmount().doubleValue())
                    .setScale(2, BigDecimal.ROUND_HALF_UP);
            parameters.put("amount", amount.toString());
            parameters.put("returnCode", returnCode);
            parameters.put("returnMessage", "");
            parameters.put("merchantKey", account.getKey());
            String[] keys = { "merchantId", "responseMode", "orderId",
                    "currencyType", "amount", "returnCode", "returnMessage",
                    "merchantKey" };
            parameters.put("mac", getMac(keys, parameters));
            String merchantUrl = trans.getSellerUrl();
            try {
                IOUtil.postUrl(merchantUrl, parameters);
            } catch (IOException e) {
                throw LinkBankException.REACHLESS_RESPONSE;
            }
        }
    }

    public void backgroundResponseByTransId(String transId)
            throws LinkBankException {
        Transaction trans = this.transactionTemplate
                .getTransactionByTranId(transId);
        backgroundResponseTransaction(trans);
    }

    private void saveTransaction(Transaction tran) {
        ActionType actionType = tran.getActionType();
        TransactionFactory tranFactory = new GetTransactionImpl()
                .getTransaction(actionType.getId().toString());
        tranFactory.saveTransaction(tran);
    }

    public Transaction saveTransaction(String transId,
            UnsPayRequest unsPayRequest) {
        Transaction trans = null;
        if (transId != null) {
            trans = this.transactionTemplate.getTransactionByTranId(transId);
        } else {
            transId = UniqueIdentityUtil.getTransactionSequence();
        }
        if (trans == null) {
            trans = new Transaction();
            trans.setTransId(transId);
        }

        // 已确认交易不做重复保存操作
        if (this.transactionTemplate.isAffirmedTransaction(trans)) {
            return trans;
        }

        if (trans.getId() == null) {// 若为新建交易
            Account creditAccount = unsPayRequest.getCreditAccount();
            SubAccount creditSubAccount = unsPayRequest.getCreditSubAccount();
            if (creditSubAccount == null) { // 未指定子账户，则使用默认子账户
                creditSubAccount = creditAccount.getDefaultSubAccount();
            }
            trans.setDebit(unsPayRequest.getDebitSubAccount());
            trans.setCredit(creditSubAccount);
            // 封装插入日期和修改日期
            WeatherUtil.fillCreateAndUpdateInfo(trans, creditAccount
                    .getAccountId());
        } else {
            trans.setUpdateTime(new Date());
            trans.setUpdateUser(trans.getCredit().getAccount().getAccountId());
        }

        ActionType actionType = unsPayRequest.getActionType();
        trans.setActionType(actionType);
        trans.setOperate(Constant.MODEL_TYPE_BANKDEPOSIT);
        if (trans.getDebit() == null) {
            trans.setDebit(this.accountTemplate.getBankSubAccount());
        }
        Date date = unsPayRequest.getTime();
        if (date == null) {
            date = new Date();
        }
        trans.setBeginDate(date);

        if (unsPayRequest.isAffirmable()) {
            // 需要确认的交易，内部状态设为'N'，交易状态为"待银行反馈"
            trans.setInsideStatus(Constant.INSIDE_STATUS_NO);
            trans.setTransStatus(Constant.TRANS_STATUS_WAITEBANKFEEDBACK);
        } else {
            // 不需要确认的交易，内部状态设为'Y'
            trans.setInsideStatus(Constant.INSIDE_STATUS_YES);
            if (unsPayRequest.isAssuredPay()) {
                // 担保交易状态为"等待卖方发货"
                trans.setTransStatus(Constant.TRANS_STATUS_WAITFORBUYER);
            } else {
                // 非担保交易状态为"交易成功"
                trans.setTransStatus(Constant.TRANS_STATUS_TRANSACTIONSUCCESS);
            }
        }

        if (Constant.ACTION_TYPE_INNER_TRANS.equals(unsPayRequest
                .getActionType().getActionId())) {
            String tradeType = unsPayRequest.isAssuredPay() ? Constant.TRADE_TYPE_ASSURE
                    : Constant.TRADE_TYPE_NOASSURE;
            trans.setTradeType(tradeType);
        }
        BigDecimal amount = unsPayRequest.getAmount();
        trans.setAmount(new Double(amount.doubleValue()));
        wireTransactionFormMerchant(trans, unsPayRequest);

        saveTransaction(trans);

        return trans;
    }

    public void wireTransactionFormMerchant(Transaction trans,
            UnsPayRequest unsPayRequest) {
        trans.setCurrency(unsPayRequest.getCurrencyType());
        if (unsPayRequest.getBank() != null)
            trans.setBankSeq(unsPayRequest.getBank().getId());
        trans.setSellerUrl(unsPayRequest.getMerchantUrl());
        trans.setOrderId(unsPayRequest.getOrderId());
        trans.setSellerParam(String.valueOf(unsPayRequest.getResponseMode()));
        trans.setCommodityInfo(unsPayRequest.getCommodity());
        trans.setOrderUrl(unsPayRequest.getOrderUrl());
        trans.setRemark(unsPayRequest.getRemark());
        trans.setMac(unsPayRequest.getMerchantMac());
        trans.setPersonName(unsPayRequest.getDebitName());
        trans.setPersonMail(unsPayRequest.getDebitEmail());
        trans.setPersonMobile(unsPayRequest.getDebitMobile());
    }

    public void affirmTransaction(String transId, UnsPayResponse unsPayResponse)
            throws LinkBankException {
        Transaction trans = this.transactionTemplate
                .getTransactionByTranId(transId);
        if (this.transactionTemplate.isAffirmedTransaction(trans))
            return;
        if (unsPayResponse.isSuccessful()) {
            trans.setTransStatus(Constant.TRANS_STATUS_TRANSACTIONSUCCESS);
            trans.setInsideStatus(Constant.INSIDE_STATUS_YES);
        } else if (unsPayResponse.isPaid()) {
            trans.setTransStatus(Constant.TRANS_STATUS_WAITFORBUYER);
            trans.setInsideStatus(Constant.INSIDE_STATUS_YES);
        } else {
            return; // 银行反馈不成功则不更改交易状态，避免银行反馈交易中间状态时，误判为交易失败
            // trans.setTransStatus(Constant.TRANS_STATUS_TRANSACTIONFAIL);
            // trans.setInsideStatus(Constant.INSIDE_STATUS_NO);
        }
        trans.setBankResponse(unsPayResponse.getReturnCode());
        Date date = new Date();
        trans.setEndDate(date);
        trans.setUpdateTime(date);
        
        // zln 修正 增加卡号返回保存
        if (unsPayResponse.getCardNo() != null
				&& unsPayResponse.getCardNo().trim().length() > 0) {
        	trans.setCardNo(unsPayResponse.getCardNo());
        }
        saveTransaction(trans);

        if (unsPayResponse.isPaid()) { // 担保交易支付成功后从后台发送反馈信息
            backgroundResponseTransaction(trans);
        }
    }

    public void wireWebPayRequestForm(WebPayRequestForm form, String transId) {
        Transaction trans = this.transactionTemplate
                .getTransactionByTranId(transId);
        if (trans == null) {
            return;
        }
        form.setMerchantId(trans.getCredit().getAccount().getAccountId());
        form.setAmount(trans.getAmount().toString());
        boolean assured = Constant.TRADE_TYPE_ASSURE.equals(trans
                .getTradeType());
        form.setAssured(assured);
        form.setOrderId(trans.getOrderId());
        form.setTransId(trans.getTransId());
        form.setCurrencyType(trans.getCurrency());
        form.setTime(DateUtil.date2String(trans.getBeginDate(),
                WebPayService.ORDER_TIME_FORMAT));
        String responseMode = trans.getSellerParam();
        if (responseMode == null || responseMode.length() == 0)
            responseMode = String.valueOf(Constant.RESPONSE_MODE_PAGE);
        form.setResponseMode(responseMode);
        form.setRemark(trans.getRemark());
    }

    public String getAccountKey(String accountId) {
        Account account = this.accountTemplate.getAccountByAccountId(accountId);
        return account == null ? null : account.getKey();
    }

    public Bank[] getSupportedNetBanks() {
        Bank[] banks = this.bankB2cNetPayService.getSupportedBanks();
        Bank[] b2bSupportedBanks = this.bankB2bNetPayService
                .getSupportedBanks();
        for (int i = 0; i < banks.length; i++) {
            String bankCode = banks[i].getBankCode();
            for (int j = 0; j < b2bSupportedBanks.length; j++) {
                if (bankCode.equals(b2bSupportedBanks[j].getBankCode())) {
                    banks[i].setB2bSupported(true);
                }
            }
        }
        
        // zln 修正 2008-3-24 按照pri对银行排序
        List listBanks = Arrays.asList(banks);
        List sortFields = new ArrayList();
        Comparator mycmp = ComparableComparator.getInstance();    
        mycmp = ComparatorUtils.nullLowComparator(mycmp);   
        sortFields.add(new BeanComparator("pri",mycmp));    
        ComparatorChain multiSort = new ComparatorChain(sortFields);
        Collections.sort(listBanks,multiSort);
        
        return banks;
    }

    public Bank[] getSupportedTelBanks() {
        return this.bankTelPayService.getSupportedBanks();
    }

    public boolean isBankNetPayMode(UnsPayRequest unsPayRequest) {
        String actionType = unsPayRequest.getActionType().getActionId();
        return Constant.ACTION_TYPE_B2C_NET_INPOUR.equals(actionType)
                || Constant.ACTION_TYPE_B2C_NET_PAY.equals(actionType)
                || Constant.ACTION_TYPE_B2B_NET_INPOUR.equals(actionType)
                || Constant.ACTION_TYPE_B2B_NET_PAY.equals(actionType)
                || Constant.ACTION_TYPE_INTL_NET_PAY.equals(actionType);
    }

    public boolean isBankTelPayMode(UnsPayRequest unsPayRequest) {
        String actionType = unsPayRequest.getActionType().getActionId();
        return Constant.ACTION_TYPE_B2C_TEL_INPOUR.equals(actionType)
                || Constant.ACTION_TYPE_B2C_TEL_PAY.equals(actionType);
    }

    public boolean isBankCodeSupported(String version) {
        return VERSION_BANK_CODE_SUPPORTED.compareTo(version) <= 0;
    }

    public String generateLicense(String merchantId, String orderId) {
        return new MD5().getMD5ofStr(merchantId + orderId);
    }

	public String getBankCodeByLinkCode(String linkeCode) {
		Bank bank = this.bankDao.getBankByLinkCode(linkeCode);
		if(bank == null) {
			return null;
		}
		return bank.getBankCode();
	}
    
}
